
#include"napi/native_api.h"
#include"napi/native_node_api.h"

#include"refbase.h"
#include"iservice_registry.h"
#include<string>
#include"usart.h"
#include"hilog/log_cpp.h"
#include <cstring>
#include "usart_proxy.h"

#include "utils/log.h"
#include <algorithm>


struct AsyncCallbackInfo {
    napi_env env;
    napi_async_work asyncWork;
    napi_deferred deferred;
};
namespace Usart_NAPI{

using namespace OHOS;
using namespace OHOS::Usart_Standard;
using OHOS::HiviewDFX::HiLog;
using std::string;

enum ALL_PORTS{
DEV_TTYAMA0 =0,
DEV_TTYS7=1,
NUM_OF_PORTS,
};
const static char* array_of_ports[]={"/dev/ttyAMA0","/dev/ttyS7"};

namespace {
//constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, 0xD001800, "Usart_NAPI"};

inline sptr<IUsartAbility> getUsartManager(){
	auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();

    if (samgr == nullptr) {
        HILOG_INFO("[Wang Napi] Failed to get System ability manager");
        return nullptr;
    }
    auto object = samgr->GetSystemAbility(USART_SERVICE_ID);
	if(object ==nullptr){
		HILOG_INFO("[Wang Napi] samgr->GetSystemAbility failed");
        return nullptr;
	}
	sptr<IUsartAbility> us = iface_cast<IUsartAbility>(object);
	if(us ==nullptr){
		HILOG_INFO("[Wang Napi] iface_cast failed");
        return nullptr;
	}
	return us;
}

//wang制作缓冲区辅助函数
napi_value wang_create_typed_array_from_string(napi_env env,const string& str){
	napi_value array_buffer,typed_array;
	uint8_t *raw_arraybuffer_buf;
	const size_t len=str.length(),len_in_bytes=len*sizeof(uint8_t);
	NAPI_CALL(env,napi_create_arraybuffer(
		env,
		len_in_bytes,
		reinterpret_cast<void**>(&raw_arraybuffer_buf),
		&array_buffer
	));

	memcpy(raw_arraybuffer_buf,str.c_str(),len_in_bytes);

	NAPI_CALL(env,napi_create_typedarray(
		env,
		napi_typedarray_type::napi_uint8_array,
		len,
		array_buffer,
		0,
		&typed_array
	));
	return typed_array;
}

//一次性字符串缓冲区
struct strbuf{
	char* ptr;
	size_t size;
	strbuf(size_t _size){size=_size;ptr=new char[_size];}
	~strbuf(){delete ptr;}
	operator std::string(){	return std::string(ptr,size);} 
};

string wang_get_name_from_napi_value(napi_env env,napi_value arg){
	
	int64_t name_enum;
	NAPI_CALL(env,napi_get_value_int64(env,arg,&name_enum));
	if(name_enum>=0&&name_enum<NUM_OF_PORTS){
		const string name = array_of_ports[name_enum];
		HILOG_INFO("[Wang Napi] wang_get_name_from_napi_value -- casted string  = %{public}s",name.c_str());
		return name;
	}
	else{
		HILOG_ERROR("[Wang Napi] wang_get_name_from_napi_value !! invalidate port name ");
		return "<error invalidate port name>";
	}

	return "<error invalidate port name>";
}


template<size_t N>
struct napi_args{
	const static size_t ARGC_ideal=N;
	size_t argc;
	napi_value argv[N];
	napi_args(napi_env env, napi_callback_info info){
		argc=ARGC_ideal;
		napi_get_cb_info(env, info, &argc,argv, nullptr, nullptr);
	}
	constexpr napi_value& operator[](size_t index){return argv[index];}
};


//用来承载typearray信息的临时类
struct typearray_infopack{
	napi_typedarray_type type;size_t length;
	void* data;napi_value array_buffer;size_t byte_offset;
	typearray_infopack()=default;
	typearray_infopack& init_from(napi_env env,napi_value arg){
		napi_get_typedarray_info(env,arg,&type,&length,&data,&array_buffer,&byte_offset);
		return *this;
	};
	constexpr char& byte(size_t index){return static_cast<char*>(data)[index];}
	string to_string(){
		return string((char*)data,length);
	}
};

} //namespace <anonymous>


std::recursive_mutex PORTS_MUTEX;






// function open(name:ALL_PORTS);

napi_value open(napi_env env, napi_callback_info info){
	auto _g = std::lock_guard(PORTS_MUTEX);
	HILOG_INFO("[Wang Napi] open\n");
	napi_args<1> args(env,info);

	string name = wang_get_name_from_napi_value(env,args[0]);

	sptr<IUsartAbility>us= getUsartManager();
	if(us==nullptr){
		HILOG_INFO("[LC] us is null!");
		return nullptr;
	}

	HILOG_INFO("[LC] napi open -> manager open!");
	HILOG_INFO("[Wang Napi] open >> us->open");
	us->open(name);
	HILOG_INFO("[Wang Napi] open << \n");
    return nullptr;
}
// function close(deviceName:enum):void;
napi_value close(napi_env env, napi_callback_info info){
	auto _g = std::lock_guard(PORTS_MUTEX);
	napi_args<1> args(env,info);
	string buf = wang_get_name_from_napi_value(env,args[0]);

	sptr<IUsartAbility>us= getUsartManager();
	if(us==nullptr){
		return nullptr;
	}
	us->close(buf);
    return nullptr;
}
// function isOpen(deviceName:enum):boolean;
napi_value isOpen(napi_env env, napi_callback_info info){
	auto _g = std::lock_guard(PORTS_MUTEX);
	HILOG_INFO("[Wang Napi] isOpen\n");
	napi_args<1> args(env,info);
	string name = wang_get_name_from_napi_value(env,args[0]);

	sptr<IUsartAbility>us= getUsartManager();
	if(us==nullptr){
		HILOG_INFO("[Wang Napi] isOpen << nullptr\n");
		return nullptr;
	}
	bool res=us->is_open(name);

	napi_value result;
	NAPI_CALL(env,napi_create_int32(env,res?1:0,&result));

	HILOG_INFO("[Wang Napi] isOpen << %s\n",(res?"true":"false"));
    return result;
}

// function read(deviceName:enum,bytes:number):string;
napi_value read(napi_env env, napi_callback_info info){
	auto _g = std::lock_guard(PORTS_MUTEX);
	napi_args<2> args(env,info);
	HILOG_INFO("[Wang Napi] read\n");
	string name = wang_get_name_from_napi_value(env,args[0]);

	int64_t readlen;
	NAPI_CALL(env,napi_get_value_int64(env,args[1],&readlen));

	sptr<IUsartAbility>us= getUsartManager();
	if(us==nullptr){
		return nullptr;
	}

	string res=us->read(name,std::abs(readlen));
	
	napi_value result=wang_create_typed_array_from_string(env,res);
	HILOG_INFO("[Wang Napi] read << %{public}s\n",res.c_str());
    return result;
}
// function readline(deviceName:enum):string;
napi_value readline(napi_env env, napi_callback_info info){
	HILOG_INFO("[Wang Napi] readline\n");
	auto _g = std::lock_guard(PORTS_MUTEX);
	napi_args<1> args(env,info);
	string name=wang_get_name_from_napi_value(env,args[0]);
	
	sptr<IUsartAbility>us= getUsartManager();
	if(us==nullptr){
		return nullptr;
	}
	string res=us->readline(name);
	
	napi_value result=wang_create_typed_array_from_string(env,res);
	HILOG_INFO("[Wang Napi] readline << %{public}s\n",res.c_str());
    return result;
}





// function write(deviceName:enum,data:string):void;
napi_value write(napi_env env, napi_callback_info info){
	auto _g = std::lock_guard(PORTS_MUTEX);
	napi_args<2> args(env,info);
	HILOG_INFO("[Wang Napi] write\n");
	string name =wang_get_name_from_napi_value(env,args[0]);	

	typearray_infopack tpinfo;
	tpinfo.init_from(env,args[1]);

	sptr<IUsartAbility>us= getUsartManager();
	if(us==nullptr){
		return nullptr;
	}
	string str_to_write = tpinfo.to_string();
	HILOG_INFO("[Wang Napi] write -- string to write is %{public}s\n",str_to_write.c_str());
	us->write(name, str_to_write);
	return nullptr;
}

napi_value beginLoopReading(napi_env env, napi_callback_info info){
	auto _g = std::lock_guard(PORTS_MUTEX);
	napi_args<1> args(env,info);
	HILOG_INFO("[Wang Napi] beginByteQueueWriting\n");
	string name = wang_get_name_from_napi_value(env,args[0]);

	sptr<IUsartAbility>us= getUsartManager();
	if(us==nullptr){
		return nullptr;
	}
	us->begin_read_loop(name);
	
	HILOG_INFO("[Wang Napi] beginByteQueueWriting <<\n");
    return nullptr;
}

napi_value endByteLoopReading(napi_env env, napi_callback_info info){
	auto _g = std::lock_guard(PORTS_MUTEX);
	napi_args<1> args(env,info);
	HILOG_INFO("[Wang Napi] endByteQueueWriting\n");
	string name = wang_get_name_from_napi_value(env,args[0]);

	sptr<IUsartAbility>us= getUsartManager();
	if(us==nullptr){
		return nullptr;
	}
	us->end_read_loop(name);
	
	HILOG_INFO("[Wang Napi] endByteQueueWriting <<\n");
    return nullptr;
}

napi_value readFromLoopingQueue(napi_env env, napi_callback_info info){
	HILOG_INFO("[Wang Napi] readFromLoopingQueue\n");
	auto _g = std::lock_guard(PORTS_MUTEX);
	napi_args<1> args(env,info);
	string name=wang_get_name_from_napi_value(env,args[0]);
	
	sptr<IUsartAbility>us= getUsartManager();
	if(us==nullptr){
		return nullptr;
	}
	string res=us->read_from_looper(name);
	
	napi_value result=wang_create_typed_array_from_string(env,res);
	HILOG_INFO("[Wang Napi] readFromLoopingQueue << \n");
    return result;
}

}//namespace Usart_NAPI

// function open(deviceNum:AllUsartPorts);
// function isOpen(deviceName:enum):boolean;
// function close(deviceName:enum):void;
// function read(deviceName:enum,bytes:number):string;
// function readline(deviceName:enum):string;
// function write(deviceName:enum,data:string):void;
    // function beginByteQueueWriting(deviceName:AllUsartPorts):void;
    // function endByteQueueWriting(deviceName:AllUsartPorts):void;
    // function readFromLoopingQueue(name:AllUsartPorts):Uint8Array;
//napi函数的名称和对应C/C++函数指针
//之前写错了：DECLARE_NAPI_STATIC_FUNCTION(错的"readLine"不要复制，正确的是"readline", Usart_NAPI::readline),
const static napi_property_descriptor desc[] = {
	DECLARE_NAPI_STATIC_FUNCTION("open", Usart_NAPI::open),
	DECLARE_NAPI_STATIC_FUNCTION("close", Usart_NAPI::close),
	DECLARE_NAPI_STATIC_FUNCTION("isOpen", Usart_NAPI::isOpen),
	DECLARE_NAPI_STATIC_FUNCTION("read", Usart_NAPI::read),
	DECLARE_NAPI_STATIC_FUNCTION("readline", Usart_NAPI::readline),
	DECLARE_NAPI_STATIC_FUNCTION("write", Usart_NAPI::write),
	DECLARE_NAPI_STATIC_FUNCTION("beginByteQueueWriting", Usart_NAPI::beginLoopReading),
	DECLARE_NAPI_STATIC_FUNCTION("endByteQueueWriting", Usart_NAPI::endByteLoopReading),
	DECLARE_NAPI_STATIC_FUNCTION("readFromLoopingQueue", Usart_NAPI::readFromLoopingQueue),
};
extern "C"{
// 模块导出入口函数
static napi_value AppExport(napi_env env, napi_value exports){ 
	HILOG_INFO("[Wang Napi] AppExport\n");
    NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
	HILOG_INFO("[Wang Napi] AppExport <<\n");
    return exports;
}
}//extern c


// app模块描述
static napi_module appModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = AppExport,
    .nm_modname = "usart",
    .nm_priv = ((void*)0),
    .reserved = {0}
};

// 注册模块
//之前写的是 AppRegister
// extern "C" __attribute__((constructor)) void AppRegister()
extern "C" __attribute__((constructor)) void RegisterModule(void)
{
	HILOG_INFO("[Wang Napi] AppRegister -- begin to add usart js module\n");
    napi_module_register(&appModule);
}